package zwatcher

import (
	"context"
	"time"

	"gitee.com/youkelike/ziam/gshutdown"
	genericoptions "gitee.com/youkelike/ziam/zoptions/options"
	"gitee.com/youkelike/ziam/zorm/store/mysql"
	"gitee.com/youkelike/ziam/zwatcher/config"
	"gitee.com/youkelike/ziam/zwatcher/options"
	"gitee.com/youkelike/zlog"
)

type watcherServer struct {
	gs             *gshutdown.GracefulShutdown
	cron           *watchJob
	redisOptions   *genericoptions.RedisOptions
	mysqlOptions   *genericoptions.MySQLOptions
	watcherOptions *options.WatcherOptions
}

type preparedWatcherServer struct {
	*watcherServer
}

func createWatcherServer(cfg *config.Config) *watcherServer {
	server := &watcherServer{
		gs:             gshutdown.New(),
		redisOptions:   cfg.RedisOptions,
		mysqlOptions:   cfg.MySQLOptions,
		watcherOptions: cfg.WatcherOptions,
	}
	return server
}

func (s *watcherServer) PrepareRun() preparedWatcherServer {
	// 初始化数据库连接池，并添加回调关闭数据库
	store, err := mysql.GetMysqlFactoryOr(s.mysqlOptions)
	if err != nil {
		panic(err)
	}
	s.gs.AddShutdownCallback(gshutdown.ShutdownFunc(func() error {
		zlog.Infow("mysql stopped.")
		return store.Close()
	}))

	// 初始化 watch job，并添加回调关闭任务，
	// 分布式锁只在 cron 里用到，就在这里构造，
	s.cron = newWatchJob(s.redisOptions, s.watcherOptions).addWatchers()
	s.gs.AddShutdownCallback(gshutdown.ShutdownFunc(func() error {
		ctx := s.cron.Stop()
		select {
		case <-ctx.Done():
			zlog.Infow("cron jobs stopped.")
		case <-time.After(time.Minute * 3):
			zlog.Errorw("context was not done in 3 minutes.")
		}
		return nil
	}))

	return preparedWatcherServer{s}
}

func (s preparedWatcherServer) Run() error {
	s.gs.Start()
	defer s.gs.Wait(context.Background())

	zlog.Infow("star to run cron jobs.")
	s.cron.Start()

	zlog.Infow("server exit")
	return nil
}
